package com.nanyang.tms.manager.bill.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.nanyang.common.core.dict.CommonEnum;
import com.nanyang.common.core.domain.ApiResult;
import com.nanyang.common.core.page.PageBean;
import com.nanyang.common.core.page.PageTableBean;
import com.nanyang.common.third.bos.entity.ObsRequestEntity;
import com.nanyang.common.third.bos.util.HwObsUtil;
import com.nanyang.common.tool.utils.convert.BeanUtils;
import com.nanyang.common.tool.utils.excel.AnalytExcel;
import com.nanyang.common.tool.utils.uuid.GlobalIdGeneratorUtil;
import com.nanyang.common.tool.utils.uuid.UUIDUtil;
import com.nanyang.sys.api.dto.request.obsauth.ObsAuthGetFilePathRequest;
import com.nanyang.sys.api.dto.response.obsauth.ObsAuthGetFilePathResponse;
import com.nanyang.sys.api.service.obsauth.ObsAuthRpcService;
import com.nanyang.tms.common.config.HwObsConfig;
import com.nanyang.tms.common.contstant.TmsSerializeConstant;
import com.nanyang.tms.common.dict.TmsCommonEnum;
import com.nanyang.tms.common.dict.TmsExceptionEnum;
import com.nanyang.tms.common.exception.TmsManagerException;
import com.nanyang.tms.common.util.RpcCheckUtils;
import com.nanyang.tms.common.util.TmsExceptionUtil;
import com.nanyang.tms.dao.bill.BillDao;
import com.nanyang.tms.dao.bill.BillRecordDao;
import com.nanyang.tms.dao.waybill.WaybillDao;
import com.nanyang.tms.dao.waybill.WaybillPayFeeDao;
import com.nanyang.tms.domain.bill.*;
import com.nanyang.tms.domain.waybill.WaybillVO;
import com.nanyang.tms.manager.bill.BillManager;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Component("billManager")
public class BillManagerImpl implements BillManager {
    @Autowired
    private BillDao billDao;
    @Autowired
    private BillRecordDao billRecordDao;
    @Autowired
    private GlobalIdGeneratorUtil globalIdGeneratorUtil;
    @Autowired
    private HwObsConfig hwObsConfig;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Reference(version = "1.0.0", timeout = 10000, check = false)
    private ObsAuthRpcService obsAuthRpcService;
    @Autowired
    private WaybillDao waybillDao;
    @Autowired
    private WaybillPayFeeDao waybillPayFeeDao;
    @Override
    public PageBean<BillVO> listBill(BillQuery query) {
        try {
            if (query == null) {
                log.error(TmsCommonEnum.PARAM_IS_NULL.getCode() + TmsCommonEnum.PARAM_IS_NULL.getMessage());
                throw new TmsManagerException(TmsCommonEnum.PARAM_IS_NULL.getCode() ,TmsCommonEnum.PARAM_IS_NULL.getMessage());
            }
            Integer count = billDao.countBill(query);
            PageBean<BillVO> page = new PageTableBean<BillVO>(query.getPageIndex(), query.getPageSize());
            if (null != count && count != 0) {
                page.setTotalItem(count);
                int startRow = page.getStartRow();
                if (startRow > 0) {
                    startRow -= 1;
                }
                query.setStartRow(startRow);
                page.addAll(billDao.listBill(query));
            }
            return page;
        } catch (Exception e) {
            throw TmsExceptionUtil.wrapException(e);
        }
    }

    @Override
    public PageBean<BillRecordVO> listBillRecord(BillRecordQuery query) {
        try {
            if (query == null) {
                log.error(TmsCommonEnum.PARAM_IS_NULL.getCode() + TmsCommonEnum.PARAM_IS_NULL.getMessage());
                throw new TmsManagerException(TmsCommonEnum.PARAM_IS_NULL.getCode() ,TmsCommonEnum.PARAM_IS_NULL.getMessage());
            }
            Integer count = billRecordDao.countBillRecord(query);
            PageBean<BillRecordVO> page = new PageTableBean<BillRecordVO>(query.getPageIndex(), query.getPageSize());
            if (null != count && count != 0) {
                page.setTotalItem(count);
                int startRow = page.getStartRow();
                if (startRow > 0) {
                    startRow -= 1;
                }
                query.setStartRow(startRow);
                page.addAll(billRecordDao.listBillRecord(query));
            }
            return page;
        } catch (Exception e) {
            throw TmsExceptionUtil.wrapException(e);
        }
    }

    @Override
    public void addBill(BillDO billDO) {
        try {
            ObsAuthGetFilePathRequest request=new ObsAuthGetFilePathRequest();
            request.setSignUrl(billDO.getBillUrl());
            ApiResult<ObsAuthGetFilePathResponse> filePathBySignUrl = obsAuthRpcService.getFilePathBySignUrl(request);
            if(RpcCheckUtils.isRpcInvokeError(filePathBySignUrl)){
                throw new TmsManagerException(TmsExceptionEnum.SIGN_URL_FAIL.getCode(),TmsExceptionEnum.SIGN_URL_FAIL.getMessage());
            }
            billDO.setBillUrl(filePathBySignUrl.getData().getFilePath());
            billDO.setBillCode(TmsSerializeConstant.BILL_KEY+globalIdGeneratorUtil.getNextSeq(TmsSerializeConstant.BILL_SEQ_KEY, TmsSerializeConstant.SEQ_INCRBY));
            billDao.insert(billDO);
        } catch (TmsManagerException e) {
            throw TmsExceptionUtil.wrapException(e);
        }
    }

    @Override
    @Transactional
    public void checkBill(BillDO billDO) {
        try {
            BillVO billVO = billDao.selectByCode(billDO.getBillCode());
            if(ObjectUtil.isNull(billVO)){
                throw new TmsManagerException(CommonEnum.NO_CONTENT.getCode(),CommonEnum.NO_CONTENT.getMessage());
            }
            if(billDao.updateState(2,0,billDO.getBillCode())<=0){//待处理-》对账中
                throw new TmsManagerException(TmsExceptionEnum.BILL_STATE_CHECK.getCode(),TmsExceptionEnum.BILL_STATE_CHECK.getMessage());
            }
            //发个MQ消息
            rocketMQTemplate.asyncSend("billCheck", billDO.getBillCode(), new SendCallback() {
                @Override
                public void onSuccess(SendResult sendResult) {
                    log.info(sendResult.toString());
                }
                @Override
                public void onException(Throwable e) {
                    throw new TmsManagerException(CommonEnum.SYSTEM_EXCEPTION.getCode(),CommonEnum.SYSTEM_EXCEPTION.getMessage(), e);
                }
            });
        } catch (TmsManagerException e) {
            throw TmsExceptionUtil.wrapException(e);
        }
    }
    @Override
    @Transactional
    public void solveBill(BillDO billDO) {
        try {
            BillVO billVO = billDao.selectByCode(billDO.getBillCode());
            if(ObjectUtil.isNull(billVO)){
                throw new TmsManagerException(CommonEnum.NO_CONTENT.getCode(),CommonEnum.NO_CONTENT.getMessage());
            }
            if(billDao.updateState(3,1,billDO.getBillCode())<=0){//对账完成-》差异处理中
                throw new TmsManagerException(TmsExceptionEnum.BILL_STATE_CHECK.getCode(),TmsExceptionEnum.BILL_STATE_CHECK.getMessage());
            }
            //发个MQ消息
            rocketMQTemplate.asyncSend("billSolve", billDO.getBillCode(), new SendCallback() {
                @Override
                public void onSuccess(SendResult sendResult) {
                    log.info(sendResult.toString());
                }
                @Override
                public void onException(Throwable e) {
                    throw new TmsManagerException(CommonEnum.SYSTEM_EXCEPTION.getCode(),CommonEnum.SYSTEM_EXCEPTION.getMessage(), e);
                }
            });
        } catch (TmsManagerException e) {
            throw TmsExceptionUtil.wrapException(e);
        }
    }
    @Override
    @Transactional
    public void syncCheckBill(String billCode) {
        try {
            BillVO billVO = billDao.selectByCode(billCode);
            if(ObjectUtil.isNull(billVO)){
                throw new TmsManagerException(CommonEnum.NO_CONTENT.getCode(),CommonEnum.NO_CONTENT.getMessage());
            }
            if(billDao.updateState(1,2,billCode)<=0){//对账中-》对账完成
                throw new TmsManagerException(TmsExceptionEnum.BILL_STATE_CHECK.getCode(),TmsExceptionEnum.BILL_STATE_CHECK.getMessage());
            }
            List<BillRecordDO> billRecordDOS = excelData(billVO.getBillCode(), billVO.getBillUrl());

              Integer billDiffNum = 0;
              Integer billNum= 0;
              BigDecimal billWeight = new BigDecimal(0);
              BigDecimal billAmount= new BigDecimal(0);
              BigDecimal sysAmount= new BigDecimal(0);
              BigDecimal billDiffAmount= new BigDecimal(0);
              BigDecimal billChargeWeight= new BigDecimal(0);
                if(CollectionUtil.isNotEmpty(billRecordDOS)){
                    billNum=billRecordDOS.size();
                    for (BillRecordDO billRecordDO : billRecordDOS) {
                        if(ObjectUtil.isNotEmpty(billRecordDO.getIsDiff()) && billRecordDO.getIsDiff()==1){
                            billDiffNum+=1;
                        }
                        if(ObjectUtil.isNotEmpty(billRecordDO.getRecordWeight())){
                            billWeight.add(billRecordDO.getRecordWeight());
                        }
                        if(ObjectUtil.isNotEmpty(billRecordDO.getRecordAmount())){
                            billAmount.add(billRecordDO.getRecordAmount());
                        }
                        if(ObjectUtil.isNotEmpty(billRecordDO.getRecordChargeWeight())){
                            billChargeWeight.add(billRecordDO.getRecordChargeWeight());
                        }
                        if(ObjectUtil.isNotEmpty(billRecordDO.getAmount())){
                            sysAmount.add(billRecordDO.getAmount());
                        }
                        billRecordDO.setGmtCreatePin(billVO.getGmtModifiedPin());
                        billRecordDO.setIp(billVO.getIp());
                        billRecordDao.insert(billRecordDO);
                    }
                    billDiffAmount=billAmount.subtract(sysAmount);
                }
                BillDO billDO = new BillDO();
                billDO.setBillCode(billCode);
                billDO.setBillDiffNum(billDiffNum);
                billDO.setBillNum(billNum);
                billDO.setBillWeight(billWeight);
                billDO.setBillAmount(billAmount);
                billDO.setBillDiffAmount(billDiffAmount);
                billDO.setBillChargeWeight(billChargeWeight);
                billDao.update(billDO);
        } catch (TmsManagerException e) {
            throw TmsExceptionUtil.wrapException(e);
        }
    }
    private List<BillRecordDO> excelData(String billCode,String path) {
        try {
            ObsRequestEntity entity = new ObsRequestEntity();
            BeanUtils.copyProperties(hwObsConfig, entity);
            File file = HwObsUtil.getResourceFile(entity,path , hwObsConfig.getLocalFilePath()+ UUIDUtil.uuid()+".xlsx" );
            List<BillRecordDO> list=new ArrayList<>();
            Sheet sheet = AnalytExcel.getSheet(file, 0);
            int lastRowNum = sheet.getLastRowNum();
            for(int i=1;i<=lastRowNum;i++){
                BillRecordDO billRecordDO=new BillRecordDO();
                billRecordDO.setBillCode(billCode);
                billRecordDO.setBillRecordCode(TmsSerializeConstant.BILL_RECORD_KEY+globalIdGeneratorUtil.getNextSeq(TmsSerializeConstant.BILL_RECORD_SEQ_KEY, TmsSerializeConstant.SEQ_INCRBY));

                try {
                    Row row = sheet.getRow(i);
                    //账单信息
                    for (int j=0;j<8;j++){
                        row.getCell(j).setCellType(CellType.STRING);
                    }
                    billRecordDO.setSupplierNo(row.getCell(0).getStringCellValue());
                    billRecordDO.setRecordNum(StringUtils.isEmpty(row.getCell(1).getStringCellValue())?0:Integer.valueOf(row.getCell(1).getStringCellValue()));
                    billRecordDO.setRecordWeight(StringUtils.isEmpty(row.getCell(2).getStringCellValue())?BigDecimal.valueOf(0): new BigDecimal(row.getCell(2).getStringCellValue()));
                    billRecordDO.setRecordVolumeWeight(StringUtils.isEmpty(row.getCell(3).getStringCellValue())?BigDecimal.valueOf(0): new BigDecimal(row.getCell(3).getStringCellValue()));
                    billRecordDO.setRecordChargeWeight(StringUtils.isEmpty(row.getCell(4).getStringCellValue())?BigDecimal.valueOf(0): new BigDecimal(row.getCell(4).getStringCellValue()));
                    billRecordDO.setRecordCountyName(row.getCell(5).getStringCellValue());
                    billRecordDO.setRecordCargoTypeName(row.getCell(6).getStringCellValue());
                    billRecordDO.setRecordAmount(StringUtils.isEmpty(row.getCell(7).getStringCellValue())?BigDecimal.valueOf(0): new BigDecimal(row.getCell(7).getStringCellValue()));
                    WaybillVO waybillVO = waybillDao.selectBySupplierNo(billRecordDO.getSupplierNo());
                    if(ObjectUtil.isEmpty(waybillVO)){
                        billRecordDO.setIsDiff(2);//处理完成
                        billRecordDO.setDiffReason("系统中不存在此单号信息");
                    }else{
                        StringBuffer diffReason=new StringBuffer();
                        //系统信息
                        billRecordDO.setProductCode(waybillVO.getProductCode());
                        billRecordDO.setProductName(waybillVO.getProductName());
                        billRecordDO.setWaybillCode(waybillVO.getWaybillCode());
                        billRecordDO.setSupplierNo(waybillVO.getSupplierNo());
                        billRecordDO.setSupplierCode(waybillVO.getSupplierCode());
                        billRecordDO.setSupplierName(waybillVO.getSupplierName());

                        billRecordDO.setNum(waybillVO.getTotalNum());
                        billRecordDO.setWeight(waybillVO.getShipmentTotalWeight());
                        billRecordDO.setVolumeWeight(waybillVO.getShipmentTotalVolumeWeight());
                        billRecordDO.setChargeWeight(waybillVO.getShipmentTotalChargeWeight());
                        billRecordDO.setCountyName(waybillVO.getCountyName());
                        billRecordDO.setCountyCode(waybillVO.getCountyCode());
                        billRecordDO.setCargoTypeName(waybillVO.getShipmentCargoTypeName());
                        billRecordDO.setCargoTypeCode(waybillVO.getShipmentCargoTypeCode());
                        Double aDouble = waybillPayFeeDao.sumPayFee(waybillVO.getWaybillCode());
                        billRecordDO.setAmount(ObjectUtil.isEmpty(aDouble)?BigDecimal.valueOf(0):BigDecimal.valueOf(aDouble));

                        if(!billRecordDO.getRecordNum().equals(billRecordDO.getNum())){
                            diffReason.append("件数差异；");
                        }
                        if(billRecordDO.getRecordWeight().compareTo(billRecordDO.getWeight())!=0){
                            diffReason.append("实重差异；");
                        }
                        if(billRecordDO.getRecordVolumeWeight().compareTo(billRecordDO.getVolumeWeight())!=0){
                            diffReason.append("材积重差异；");
                        }
                        if(billRecordDO.getRecordChargeWeight().compareTo(billRecordDO.getChargeWeight())!=0){
                            diffReason.append("计费重差异；");
                        }
                        if(billRecordDO.getRecordAmount().compareTo(billRecordDO.getAmount())!=0){
                            diffReason.append("金额差异；");
                        }
                        if(StringUtils.isNotEmpty(diffReason)){
                            billRecordDO.setIsDiff(1);
                            billRecordDO.setDiffReason(diffReason.toString());
                        }else{
                            billRecordDO.setIsDiff(0);
                        }
                    }

                } catch (Exception e) {
                    log.error("处理excel异常：",path,e);
                    billRecordDO.setIsDiff(2);//处理完成
                    billRecordDO.setDiffReason(String.format(CommonEnum.SYSTEM_EXCEPTION.getMessage(),e.getMessage()));
                }
                list.add(billRecordDO);
            }
            return  list;
        } catch (IOException e) {
            log.error("获取上传文件异常：",path,e);
            throw new TmsManagerException(CommonEnum.SYSTEM_EXCEPTION.getCode(),CommonEnum.SYSTEM_EXCEPTION.getMessage()+e.getMessage());
        }
    }

    @Override
    @Transactional
    public void syncUpdateBill(List<BillRecordDO> listBill,String billCode) {
        try {
            if(billDao.updateState(4,3,billCode)<=0){//处理中-》处理完成
                throw new TmsManagerException(TmsExceptionEnum.BILL_STATE_CHECK.getCode(),TmsExceptionEnum.BILL_STATE_CHECK.getMessage());
            }
            if(CollectionUtil.isNotEmpty(listBill)){//记录错误信息更新
                listBill.forEach(billRecordDO ->{
                    billRecordDao.update(billRecordDO);
                });
            }
        } catch (TmsManagerException e) {
            throw TmsExceptionUtil.wrapException(e);
        }
    }
}
